﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Admin.NET.Application.Entity;
using Admin.NET.Core.Service;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Http;
using SqlSugar;
using Yitter.IdGenerator;

namespace Admin.NET.Application;

/// <summary>
/// 检验任务服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class inspectiontaskService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<inspectiontask> _inspectiontaskRep;
    private readonly ISqlSugarClient _sqlSugarClient;
    private readonly SysDictTypeService _sysDictTypeService;

    public inspectiontaskService(SqlSugarRepository<inspectiontask> inspectiontaskRep, ISqlSugarClient sqlSugarClient, SysDictTypeService sysDictTypeService)
    {
        _inspectiontaskRep = inspectiontaskRep;
        _sqlSugarClient = sqlSugarClient;
        _sysDictTypeService = sysDictTypeService;
    }

    /// <summary>
    /// 分页查询检验任务 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询检验任务")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<inspectiontaskOutput>> Page(PageinspectiontaskInput input)
    {
        input.Keyword = input.Keyword?.Trim();
        var query = _inspectiontaskRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.number.Contains(input.Keyword) || u.tasktype.Contains(input.Keyword) || u.roleid.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.number), u => u.number.Contains(input.number.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.tasktype), u => u.tasktype.Contains(input.tasktype.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.roleid), u => u.roleid.Contains(input.roleid.Trim()))
            .WhereIF(input.inspectionschemeid != null, u => u.inspectionschemeid == input.inspectionschemeid)
            .WhereIF(input.ticketsid != null, u => u.ticketsid == input.ticketsid)
            .LeftJoin<inspectionscheme>((u, inspectionscheme) => u.inspectionschemeid == inspectionscheme.Id)
            .LeftJoin<tickets>((u, inspectionscheme, tickets) => u.ticketsid == tickets.Id)
            .Select((u, inspectionscheme, tickets) => new inspectiontaskOutput
            {
                Id = u.Id,
                number = u.number,
                tasktype = u.tasktype,
                inspectionschemeid = u.inspectionschemeid,
                inspectionschemeFkDisplayName = $"{inspectionscheme.schemename}",
                ticketsid = u.ticketsid,
                ticketsFkDisplayName = $"{tickets.encode}",
                CreateTime = u.CreateTime,
                UpdateTime = u.UpdateTime,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                IsDelete = u.IsDelete,
                roleid = u.roleid,
            });
		return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
    }

    /// <summary>
    /// 获取检验任务详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取检验任务详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<inspectiontask> Detail([FromQuery] QueryByIdinspectiontaskInput input)
    {
        return await _inspectiontaskRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 增加检验任务 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加检验任务")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddinspectiontaskInput input)
    {
        var entity = input.Adapt<inspectiontask>();
       
        return await _inspectiontaskRep.InsertAsync(entity) ? entity.Id : 0;
    }

    /// <summary>
    /// 更新检验任务 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新检验任务")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateinspectiontaskInput input)
    {
        var entity = input.Adapt<inspectiontask>();
        await _inspectiontaskRep.AsUpdateable(entity)
        .ExecuteCommandAsync();
    }

    /// <summary>
    /// 删除检验任务 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除检验任务")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteinspectiontaskInput input)
    {
        var entity = await _inspectiontaskRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _inspectiontaskRep.FakeDeleteAsync(entity);   //假删除
        //await _inspectiontaskRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 批量删除检验任务 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除检验任务")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteinspectiontaskInput> input)
    {
        var exp = Expressionable.Create<inspectiontask>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _inspectiontaskRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        return await _inspectiontaskRep.FakeDeleteAsync(list);   //假删除
        //return await _inspectiontaskRep.DeleteAsync(list);   //真删除
    }
    
    /// <summary>
    /// 获取下拉列表数据 🔖
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取下拉列表数据")]
    [ApiDescriptionSettings(Name = "DropdownData"), HttpPost]
    public async Task<Dictionary<string, dynamic>> DropdownData(DropdownDatainspectiontaskInput input)
    {
        var inspectionschemeidData = await _inspectiontaskRep.Context.Queryable<inspectionscheme>()
            .InnerJoinIF<inspectiontask>(input.FromPage, (u, r) => u.Id == r.inspectionschemeid)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.schemename}"
            }).ToListAsync();
        var ticketsidData = await _inspectiontaskRep.Context.Queryable<tickets>()
            .InnerJoinIF<inspectiontask>(input.FromPage, (u, r) => u.Id == r.ticketsid)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.encode}"
            }).ToListAsync();
        return new Dictionary<string, dynamic>
        {
            { "inspectionschemeid", inspectionschemeidData },
            { "ticketsid", ticketsidData },
        };
    }
    
    /// <summary>
    /// 导出检验任务记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出检验任务记录")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageinspectiontaskInput input)
    {
        var list = (await Page(input)).Items?.Adapt<List<ExportinspectiontaskOutput>>() ?? new();
        if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList();
        var tasktypeDictMap = _sysDictTypeService.GetDataList(new GetDataDictTypeInput { Code = "Qualityinspection" }).Result.ToDictionary(x => x.Value, x => x.Label);
        var roleidDictMap = _sysDictTypeService.GetDataList(new GetDataDictTypeInput { Code = "Roledis" }).Result.ToDictionary(x => x.Value, x => x.Label);
        list.ForEach(e => {
            e.tasktypeDictLabel = tasktypeDictMap.GetValueOrDefault(e.tasktype ?? "", e.tasktype);
            e.roleDictLabel = roleidDictMap.GetValueOrDefault(e.roleid ?? "", e.roleid);
        });
        return ExcelHelper.ExportTemplate(list, "检验任务导出记录");
    }
    
    /// <summary>
    /// 下载检验任务数据导入模板 ⬇️
    /// </summary>
    /// <returns></returns>
    [DisplayName("下载检验任务数据导入模板")]
    [ApiDescriptionSettings(Name = "Import"), HttpGet, NonUnify]
    public IActionResult DownloadTemplate()
    {
        return ExcelHelper.ExportTemplate(new List<ExportinspectiontaskOutput>(), "检验任务导入模板", (_, info) =>
        {
            if (nameof(ExportinspectiontaskOutput.inspectionschemeFkDisplayName) == info.Name) return _inspectiontaskRep.Context.Queryable<inspectionscheme>().Select(u => $"{u.schemename}").Distinct().ToList();
            if (nameof(ExportinspectiontaskOutput.ticketsFkDisplayName) == info.Name) return _inspectiontaskRep.Context.Queryable<tickets>().Select(u => $"{u.encode}").Distinct().ToList();
            return null;
        });
    }
    
    /// <summary>
    /// 导入检验任务记录 💾
    /// </summary>
    /// <returns></returns>
    [DisplayName("导入检验任务记录")]
    [ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork]
    public IActionResult ImportData([Required] IFormFile file)
    {
        lock (this)
        {
            var tasktypeDictMap = _sysDictTypeService.GetDataList(new GetDataDictTypeInput { Code = "Qualityinspection" }).Result.ToDictionary(x => x.Label!, x => x.Value);
            var roleidDictMap = _sysDictTypeService.GetDataList(new GetDataDictTypeInput { Code = "Roledis" }).Result.ToDictionary(x => x.Label!, x => x.Value);
            var stream = ExcelHelper.ImportData<ImportinspectiontaskInput, inspectiontask>(file, (list, markerErrorAction) =>
            {
                _sqlSugarClient.Utilities.PageEach(list, 2048, pageItems =>
                {
                    // 链接 检验方案
                    var inspectionschemeidLabelList = pageItems.Where(x => x.inspectionschemeFkDisplayName != null).Select(x => x.inspectionschemeFkDisplayName).Distinct().ToList();
                    if (inspectionschemeidLabelList.Any()) {
                        var inspectionschemeidLinkMap = _inspectiontaskRep.Context.Queryable<inspectionscheme>().Where(u => inspectionschemeidLabelList.Contains($"{u.schemename}")).ToList().ToDictionary(u => $"{u.schemename}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.inspectionschemeid = inspectionschemeidLinkMap.GetValueOrDefault(e.inspectionschemeFkDisplayName ?? "");
                            if (e.inspectionschemeid == null) e.Error = "检验方案链接失败";
                        });
                    }
                    // 链接 工单
                    var ticketsidLabelList = pageItems.Where(x => x.ticketsFkDisplayName != null).Select(x => x.ticketsFkDisplayName).Distinct().ToList();
                    if (ticketsidLabelList.Any()) {
                        var ticketsidLinkMap = _inspectiontaskRep.Context.Queryable<tickets>().Where(u => ticketsidLabelList.Contains($"{u.encode}")).ToList().ToDictionary(u => $"{u.encode}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.ticketsid = ticketsidLinkMap.GetValueOrDefault(e.ticketsFkDisplayName ?? "");
                            if (e.ticketsid == null) e.Error = "工单链接失败";
                        });
                    }
                    
                    // 映射字典值
                    foreach(var item in pageItems) {
                        if (string.IsNullOrWhiteSpace(item.tasktypeDictLabel)) continue;
                        item.tasktype = tasktypeDictMap.GetValueOrDefault(item.tasktypeDictLabel);
                        if (item.tasktype == null) item.Error = "质检分类字典映射失败";
                        if (string.IsNullOrWhiteSpace(item.roleDictLabel)) continue;
                        item.roleid = roleidDictMap.GetValueOrDefault(item.roleDictLabel);
                        if (item.roleid == null) item.Error = "权限角色字典映射失败";
                    }
                    
                    // 校验并过滤必填基本类型为null的字段
                    var rows = pageItems.Where(x => {
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.inspectionschemeid == null){
                            x.Error = "检验方案不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.ticketsid == null){
                            x.Error = "工单不能为空";
                            return false;
                        }
                        return true;
                    }).Adapt<List<inspectiontask>>();
                    
                    var storageable = _inspectiontaskRep.Context.Storageable(rows)
                        .SplitError(it => it.Item.number?.Length > 100, "单号长度不能超过100个字符")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.tasktype), "质检分类不能为空")
                        .SplitError(it => it.Item.tasktype?.Length > 100, "质检分类长度不能超过100个字符")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.roleid), "权限角色不能为空")
                        .SplitError(it => it.Item.roleid?.Length > 100, "权限角色长度不能超过100个字符")
                        .SplitInsert(_ => true)
                        .ToStorage();
                    
                    storageable.BulkCopy();
                    storageable.BulkUpdate();
                    
                    // 标记错误信息
                    markerErrorAction.Invoke(storageable, pageItems, rows);
                });
            });
            
            return stream;
        }
    }
}
